package org.hxzon.demo.coyote;

import java.io.IOException;

import org.apache.coyote.Adapter;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.C2BConverter;
import org.apache.tomcat.util.net.SocketStatus;


public class StartHttp11Server {
	/** Start http on the port. It creates an internal thread pool. This method doesn't block, all processing 
     * will be done in the thread pool.
     * 
     * @param port
     * @throws Exception
     */ 
    private static void startHttp(int port) throws Exception {
    	//Http11Protocol proto=new Http11Protocol();
        Http11NioProtocol proto=new Http11NioProtocol();
        proto.setPort(port);

        proto.setAdapter(new MyAdapter());
       
        proto.init();
        proto.start();
        while(true){
        	
        }
//        System.out.println("stop");
    }

    static class MyAdapter implements Adapter {

//        public void service(Request req, Response res) throws Exception {
//            System.out.println("Incoming request " + req.queryString().toString());
//            res.setStatus(200);
//
//            // tomcat doesn't use a stream internally - so the object can be recycled and avoids
//            // buffer to buffer copy.
//
//            // To write to the stream, tomcat uses 'byte chunk' - a buffer optimized for char-byte conversions
//            // This is similar with NIO buffers
//            ByteChunk myChunk=new ByteChunk();
//
//            // let's just send some bytes - more advanced mechanism later
//            String hello="hello";
//            byte helloBytes[]=hello.getBytes();
//            myChunk.setBytes( helloBytes, 0, helloBytes.length);
//
//
//            res.doWrite(myChunk);
//        }
        protected C2BConverter getOut(final Response res) throws IOException {
            // You can fine tune the buffers. In a real app - this should be reused, this is just 
            // an example to show how the buffers are used.
            final ByteChunk myChunk=new ByteChunk( 1024 );
            myChunk.setLimit(4096);
            C2BConverter out=new C2BConverter( myChunk, "UTF8" );

            // You can set limit to -1, add to it, and explicitly write when you
            // want to, or you can have it write automatically when the buffer is filled.
            myChunk.setByteOutputChannel( new ByteChunk.ByteOutputChannel() {
                public void realWriteBytes(byte cbuf[], int off, int len) throws IOException {
                    res.doWrite(myChunk);
                }
            });
            return out;
        }

        public void service(Request req, final Response res) throws Exception {
            System.out.println("Incoming request: uri=" + req.requestURI() +
                    " queryString=" + req.queryString().toString() +
                    " protocol=" + req.protocol().toString());

            res.setStatus(200);

            res.setHeader( "foo", "bar");
            res.setContentType("text/plain");

            // We must explicitely flush the headers.
            res.sendHeaders();

            // tomcat doesn't use a stream internally - so the object can be recycled and avoids
            // buffer to buffer copy.

            // To write to the stream, tomcat uses 'byte chunk' - a buffer optimized for char-byte conversions
            // This is similar with NIO buffers
            C2BConverter out=getOut(res);


            // You can also add bytes
            //ByteChunk myChunk=out.getByteChunk();
            //String h="hellow";
            //byte hB[]=h.getBytes();
            //myChunk.append( hB, 0, hB.length);
            
            out.convert("Hello World");
            // make sure all the chars are sent to the byte[].
            // Unlike OutputStream/Writer - you can mix char and bytes, but you must remember to flush when switching.
            out.flushBuffer();

            // Send it to the stream. Output will also be sent when the buffer is full, based on the limit
            // Buffer size is set with myChunk.setLimit()
            out.getByteChunk().flushBuffer();

            // final processing
            res.finish();

            // Alternatively, you can use a growing ByteChunk and write it explicitely:
            //res.doWrite(myChunk);
            req.recycle();
            res.recycle();
        }



		@Override
		public boolean event(Request req, Response res, SocketStatus status) throws Exception {
			System.out.println(status.name());
			return false;
		}
    }
    
    public static void main(String args[]) throws Exception{
    	StartHttp11Server.startHttp(80);
    }


}
